#include"EPollPoller.h"
#include"Logger.h"
#include"Channel.h"

#include<errno.h>
#include<unistd.h>
#include<string.h>
//对应channel还未添加，已添加，已删除,对应channel的index
const int kNew = -1;
const int kAdded = 1;
const int kDeleted = 2;

EPollPoller::EPollPoller(EventLoop* loop)
    :Poller(loop), epollfd_(::epoll_create1(EPOLL_CLOEXEC)), events_(kInitEventListSize)
{
    if(epollfd_ < 0){
        LOG_FATAL("epoll_create err:%d", errno);
    }
}

EPollPoller::~EPollPoller(){
    ::close(epollfd_);
}

//给EventLoop调用
Timestamp EPollPoller::poll(int timeoutMs, ChannelList *activeChannels){
    //不开启debug模式时不输出日志，提高高并发效率 lu:long unsight
    LOG_DEBUG("func = %s => fd total count:%lu\n",__FUNCTION__, channels_.size());

    //第二个参数接收一个数组地址作为传出参数，存放有事件发生的fd，但是muduo使用的是可扩容的vector作为容器，
    //使用&*events_.begin()得到数组首地址，首先解引用得到第一个元素的值，再取地址
    int numEvents = ::epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()), timeoutMs);
    //多线程时，每个线程都有一个event_Loop,都会进行epoll_wait，此时避免都对errno进行写操作覆盖掉，此时保存
    int saveErrno = errno;
    Timestamp now(Timestamp::now()); 

    if(numEvents > 0){
        LOG_INFO("%d events happen",numEvents);
        fillActiveChannels(numEvents, activeChannels);
        if(numEvents == events_.size()){
            events_.resize(events_.size() * 2);
        }
    }else if(numEvents == 0){
        LOG_DEBUG("%s timeout\n", __FUNCTION__);
    }else{
        if(saveErrno != EINTR){
            errno = saveErrno;//因为日志访问的是errno
            LOG_ERROR("EPollPoller::poll() err");
        }
    }
    return now;
}

//更新channel，如果已经被监听，就删除或者修改，如果是新channel就加入监听
void EPollPoller::updateChannel(Channel *channel){
    const int index = channel->index();
    LOG_INFO("func = %s => fd = %d, events = %d \n, index = %d",__FUNCTION__, channel->fd(), channel->events(), index);

    if(index == kNew || index == kDeleted){
        if(index == kNew){
            int fd = channel->fd();
            channels_[fd] = channel;
        }

        channel->set_index(kAdded);
        update(EPOLL_CTL_ADD, channel);
    }else{//channel已经在epoller注册过了
        int fd = channel->fd();
        if(channel->isNoneEvent()){
            update(EPOLL_CTL_DEL, channel);
            channel->set_index(kDeleted);
        }else{
            update(EPOLL_CTL_MOD, channel);
        }
    }
}

//从poller中删除channel
void EPollPoller::removeChannel(Channel *channel){
    LOG_INFO("func = %s => fd = %d\n",__FUNCTION__, channel->fd());

    int fd = channel->fd();
    channels_.erase(fd);

    int index = channel->index();
    if(index == kAdded)
    {
        update(EPOLL_CTL_DEL, channel);
    }
    channel->set_index(kNew);
}

// 填写活跃连接
void EPollPoller::fillActiveChannels(int numEvents, ChannelList *activeChannels) const{
    for(int i = 0; i < numEvents; ++i)
    {
        Channel* channel = static_cast<Channel*>(events_[i].data.ptr);
        channel->set_revents(events_[i].events);
        activeChannels->push_back(channel);//EventLoop获取到所有发生的事件
    }
}
// 更新channel epoll_ctl_*
void EPollPoller::update(int operation, Channel *channel){
    epoll_event event;
    int fd = channel->fd();

    memset(&event, 0, sizeof(event));

    event.events = channel->events();
    event.data.fd = fd;
    event.data.ptr = channel;

    if(::epoll_ctl(epollfd_, operation, fd, &event) < 0){
        if(operation == EPOLL_CTL_DEL){
            LOG_ERROR("epoll_ctl del error:%d\n", errno);
        }else{
            LOG_FATAL("epoll_ctl del error:%d\n", errno);
        }
    }
}
